package com.mallcloud.mall.app.task.xgl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.mallcloud.mall.app.api.entity.dto.WxPay3RefundInfoDTO;
import com.mallcloud.mall.app.service.AppWxPay3Service;
import com.mallcloud.mall.common.core.constant.enums.mall.OrderEnum;
import com.mallcloud.mall.mall.api.entity.MallOrderCouponRefundModel;
import com.mallcloud.mall.mall.api.entity.MallPointsCouponOfRefundModel;
import com.mallcloud.mall.mall.api.entity.vo.MallOrderCouponVO;
import com.mallcloud.mall.mall.service.MallOrderCouponRefundService;
import com.mallcloud.mall.mall.service.MallOrderCouponService;
import com.mallcloud.mall.mall.service.MallPointsCouponOfRefundService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 星光里【立牌订单】定时处理需要退款支付订单
 */
@Slf4j
@RequiredArgsConstructor
//@Configuration      //1.主要用于标记配置类，兼备Component的效果。
//@ConditionalOnProperty("const.wxpay.v3.appId")
public class RefundJob {
    private final MallOrderCouponService orderCouponService;
    private final MallPointsCouponOfRefundService mallPointsCouponOfRefundService;
    private final MallOrderCouponRefundService orderCouponRefundService;
    private final AppWxPay3Service wx3ApiService;

    private Map<String, MallOrderCouponVO> getOrderCouponMap(List<String> orderNos) {
        List<MallOrderCouponVO> orderCouponList = orderCouponService.listByOrderNos(orderNos);
        return orderCouponList.stream().collect(Collectors.toMap(MallOrderCouponVO::getOrderNo, Function.identity()));
    }

    @SneakyThrows
    @Scheduled(cron = "0 59 23 * * ? ")
    private void xglRefundTasks() {
        log.info("=========");
        log.info("=========");
        log.info("=========");
        log.info("=========");
        log.info("星光里过期券退款....");
        List<MallPointsCouponOfRefundModel> resList = mallPointsCouponOfRefundService.list();
        if (resList.isEmpty()) {
            return;
        }
        //1.预支付订单券map
        Map<String, MallOrderCouponVO> orderCouponVoMap = getOrderCouponMap(resList.stream().map(MallPointsCouponOfRefundModel::getOrderNo).collect(Collectors.toList()));
        //2.退款券map
        Map<String, List<MallPointsCouponOfRefundModel>> refundCouponInfoMap = resList.stream().collect(Collectors.groupingBy(MallPointsCouponOfRefundModel::getOrderNo));
        //3.生成预退款单
        List<MallOrderCouponRefundModel> orderCouponRefunds = refundCouponInfoMap.entrySet().stream().map(x -> makeOrderCouponRefund(orderCouponVoMap.get(x.getKey()), x.getValue())).collect(Collectors.toList());
        Optional.ofNullable(orderCouponRefunds).ifPresent(orderCouponRefundService::saveBatch);
        //因为用户可以一次买多张券，微信订单号退款是针对整单退，所以这里根据订单查询所有订单，根据需要退款的订单进行整单退和部分订单退
        for (Map.Entry<String, List<MallPointsCouponOfRefundModel>> refundCouponEntry : refundCouponInfoMap.entrySet()) {
            String orderNo = refundCouponEntry.getKey();
			MallOrderCouponVO orderCouponVO = orderCouponVoMap.get(orderNo);
            List<MallPointsCouponOfRefundModel> refundCouponList = refundCouponEntry.getValue();
            if (refundCouponList.size() == 1) {
                //微信api退款
                wx3ApiService.refund(makeOneRefundInfo(refundCouponList.get(0)));
            }
            else if (refundCouponList.size() > 1) {
                //1查询订单全部券列表，并比对；如果是整单就整单退款，如果是部分单就部分退款
                wx3ApiService.refund(makeMultiRefundInfo(refundCouponList, orderCouponVO));
            }
        }
    }

    private WxPay3RefundInfoDTO makeMultiRefundInfo(List<MallPointsCouponOfRefundModel> refundCouponList, MallOrderCouponVO orderCouponVO) {
		WxPay3RefundInfoDTO refundInfo = new WxPay3RefundInfoDTO();
        refundInfo.setOutRefundNo(IdUtil.fastSimpleUUID());
        refundInfo.setOutTradeNo(orderCouponVO.getOrderNo());
        refundInfo.setReason("券过期自动退款");
		WxPay3RefundInfoDTO.Amount amount = refundInfo.getAmount(
                refundCouponList.get(0).getPayMoney().multiply(BigDecimal.valueOf(refundCouponList.size())).longValue(),
                orderCouponVO.getFinalMoney().longValue()
        );
        refundInfo.setAmount(amount);
        return refundInfo;
    }

    private WxPay3RefundInfoDTO makeOneRefundInfo(MallPointsCouponOfRefundModel refundCoupon) {
		WxPay3RefundInfoDTO refundInfo = new WxPay3RefundInfoDTO();
        refundInfo.setOutRefundNo(IdUtil.fastSimpleUUID());
        refundInfo.setOutTradeNo(refundCoupon.getOrderNo());
        refundInfo.setReason("券过期自动退款");
		WxPay3RefundInfoDTO.Amount amount = refundInfo.getAmount(
                refundCoupon.getPayMoney().multiply(BigDecimal.valueOf(100)).longValue(),
                refundCoupon.getPayMoney().multiply(BigDecimal.valueOf(100)).longValue()
        );
        refundInfo.setAmount(amount);
        return refundInfo;
    }

    private MallOrderCouponRefundModel makeOrderCouponRefund(MallOrderCouponVO orderCouponVO, List<MallPointsCouponOfRefundModel> refundCouponInfos) {
		MallPointsCouponOfRefundModel refundCouponInfo = refundCouponInfos.get(0);

		MallOrderCouponRefundModel orderCouponRefund = new MallOrderCouponRefundModel();
        orderCouponRefund.setOrderNo(refundCouponInfo.getOrderNo());
        orderCouponRefund.setRefundNo(IdUtil.fastSimpleUUID());
        orderCouponRefund.setStatus(OrderEnum.StatusRefundEnum.PENDING.getStatus());
        orderCouponRefund.setRefundMoney(refundCouponInfo.getPayMoney().multiply(BigDecimal.valueOf(refundCouponInfos.size())));
        orderCouponRefund.setPayMoney(orderCouponVO.getMoney());
        if(StrUtil.isBlank(orderCouponVO.getCouponIds())){
			orderCouponRefund.setNum(0);
		}else{
			orderCouponRefund.setNum(orderCouponVO.getCouponIds().split(StrUtil.COMMA).length);
		}
        orderCouponRefund.setRefundNum(refundCouponInfos.size());
        orderCouponRefund.setCouponNo("");
        orderCouponRefund.setCouponMoney(refundCouponInfo.getPayMoney());
        orderCouponRefund.setStoreNo(orderCouponVO.getStoreNo());
        orderCouponRefund.setCardNo(refundCouponInfo.getCardNo());
        orderCouponRefund.setMchId(orderCouponVO.getMchId());
        return orderCouponRefund;
    }
}